这道题算是再次更新了我对线段树的认知,果然别人家的线段树什么都能干。
题意:给定一个长度为的序列,每次删除值为当前序列长度的元素,你可以改变一些元素的使经过若干次删除后序列为空,求最少改变次数。
:另有次操作,每次改变一个元素的值或者使全部元素,操作完之后再次询问最少改变次数。
首先明白这个游戏怎么玩。
显然序列的顺序可以随便换,我们把它们丢进一个桶中,一个序列是可以被删完,当且仅当每个下标为的点右边有一个下标为的桶里装了个元素,且。
题解中有一个形象的解释:把每个元素落在它的柱子上,每落一次高度加一,推到所有柱子,刚好覆盖所有~个点。
思考不带修改怎么做,就是暴力推完柱子看有几个还没有被覆盖,空位数即答案。
为什么这是对的?
1.每次最多填补一个空位,这是显然的,即便你不是“搬运”而是直接“添加”,每次也只能填一个,所以空位数就是最优解。
2.对于每个空位,只需要找到一个被“重复覆盖”的点,把它搬到这个空位上即可。也就是说我们至少可以找到一组最优解。
那么带修怎么做呢?
第一问简直是弟弟,考试的时候我的办法是,开一个记录真实的桶里每个有多少个,每次就,反之即可。
第二问考场上了。显然是不能直接暴力全部+1的,可以用个线段树维护一下,开始把树扔在中间,然后每次平移查询的区间即可。
但是很重要的一点,移出去的柱子是不在计算贡献的。就是说一个柱子不在现在的~中,它就不能再“推到覆盖”那些点了,因为它自己这个要花费个代价移动进来,所以要把这个柱子覆盖的这些点的“被覆盖次数”,反之当区间右移的时候要更新那个新加入的柱子的贡献,也就是区间。
然而我的只做了平移,于是考试就只有了。
那么我们现在要干什么呢?
找到一种数据结构,支持区间加减,询问区间的个数。
于是线段树就出场了,事实上它可以维护区间最小值的个数,此题中只要在的时候只加上的即可。
维护两个东西:区间最小值 区间最小值出现的次数。
另外加上维护区间加减必须的加减懒标记即可。
每次的时候如果那么直接继承较小那边的信息,否则就直接把两个并起来。
的时候因为区间加减不会改变区间最小值的个数,所以只修改一个然后下传标记即可。
然后这道题就愉快的做完了。
:
1 |
|